﻿namespace CN2P.ServiceModel
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;

    using Newtonsoft.Json;

    public class FullProductModel
    {

        private readonly IDictionary<string, object> props;

        public FullProductModel()
            : this(new Dictionary<string, object>())
        {
        }

        public FullProductModel(IDictionary<string, object> props)
        {
            this.props = props;
        }

        public string ProdId
        {
            get { return this.GetString("prodId"); }
            set { this.SetStringIgnoreDefault("prodId", value); }
        }

        public string ProdName
        {
            get { return this.GetString("prodName"); }
            set { this.SetString("prodName", value); }
        }

        public string ProdDesc
        {
            get { return this.GetString("prodDesc"); }
            set { this.SetString("prodDesc", value); }
        }

        public decimal ProdPrice
        {
            get { return this.GetDecimal("prodPrice") ?? 0.0m; }
            set { this.SetDecimal("prodPrice", value); }
        }

        public string ImageUrl
        {
            get { return this.GetString("imageUrl"); }
            set { this.SetString("imageUrl", value); }
        }

        public double AverageRating
        {
            get { return this.GetDouble("averageRating") ?? 0.0; }
            set { this.SetDouble("averageRating", value); }
        }

        public string Isbn
        {
            get { return this.GetString("isbn"); }
            set { this.SetStringIgnoreDefault("isbn", value); }
        }

        public int Pages
        {
            get { return this.GetInt32("pages") ?? 0; }
            set { this.SetInt32("pages", value); }
        }

        public IList<string> Authors
        {
            get { return this.GetStringList("authors"); }
            set { this.props["authors"] = value; }
        }

        public IList<string> Tags
        {
            get { return this.GetStringList("tags"); }
            set { this.props["tags"] = value; }
        }

        public string Brand
        {
            get { return this.GetString("brand"); }
            set { this.SetStringIgnoreDefault("brand", value); }
        }

        public string Model
        {
            get { return this.GetString("model"); }
            set { this.SetStringIgnoreDefault("model", value); }
        }

        public string SerialNo
        {
            get { return this.GetString("serialNo"); }
            set { this.SetStringIgnoreDefault("serialNo", value); }
        }

        public string Size
        {
            get { return this.GetString("size"); }
            set { this.SetStringIgnoreDefault("size", value); }
        }

        public string ManufDate
        {
            get { return this.GetString("manufDate"); }
            set { this.SetStringIgnoreDefault("manufDate", value); }
        }

        public string Weight
        {
            get { return this.GetString("weight"); }
            set { this.SetStringIgnoreDefault("weight", value); }
        }

        public string ShipWeight
        {
            get { return this.GetString("shipWeight"); }
            set { this.SetStringIgnoreDefault("shipWeight", value); }
        }

        public bool HasTag(string tag)
        {
            tag = tag.ToLowerInvariant();
            return Tags.Any(item => item.ToLowerInvariant() == tag);
        }

        public bool HasTerm(string term)
        {
            if (string.IsNullOrWhiteSpace(term))
            {
                return true;
            }

            term = term.ToLowerInvariant();

            var desc = (this.ProdDesc ?? string.Empty).ToLowerInvariant();
            var title = (this.ProdName ?? string.Empty).ToLowerInvariant();

            return desc.Contains(term) || title.Contains(term);
        }

        public CartItemModel CreateCartItem()
        {
            return new CartItemModel
                {
                    ProdId = ProdId,
                    ProdDesc = ProdDesc,
                    ProdName = ProdName,
                    ImageUrl = ImageUrl,
                    ProdPrice = ProdPrice,
                    Quantity = 1
                };
        }

        public virtual IDictionary<string, object> GetProps()
        {
            return this.props;
        }

        public static FullProductModel FromJson(string content)
        {
            var props = JsonConvert.DeserializeObject<IDictionary<string,object>>(content);
            return new FullProductModel(props);
        }

        protected string GetString(string key)
        {
            object res;
            if (this.props.TryGetValue(key, out res))
            {
                return res as string;
            }

            return null;
        }

        protected decimal? GetDecimal(string key)
        {
            object res;
            if (this.props.TryGetValue(key, out res))
            {
                return Convert.ToDecimal(res);
            }

            return null;
        }

        protected double? GetDouble(string key)
        {
            object res;
            if (this.props.TryGetValue(key, out res))
            {
                return Convert.ToDouble(res);
            }

            return null;
        }

        protected int? GetInt32(string key)
        {
            object res;
            if (this.props.TryGetValue(key, out res))
            {
                return Convert.ToInt32(res);
            }

            return null;
        }

        protected IList<string> GetStringList(string key)
        {
            object res;
            if (!this.props.TryGetValue(key, out res))
            {
                return null;
            }

            var list = res as IList<string>;
            if (list != null) return list;
            var array = res as IEnumerable;
            if (array != null)
            {
                list = new List<string>();
                foreach (var item in array)
                {
                    list.Add(item.ToString());
                }

                this.props[key] = list;
                return list;
            }

            return null;
        }

        protected void SetString(string key, string value)
        {
            this.props[key] = value;
        }

        protected void SetDecimal(string key, decimal value)
        {
            this.props[key] = value;
        }

        protected void SetDouble(string key, double value)
        {
            this.props[key] = value;
        }

        protected void SetInt32(string key, int value)
        {
            this.props[key] = value;
        }

        protected void SetStringIgnoreDefault(string key, string value)
        {
            if (value != null)
            {
                this.props[key] = value;
            }
            else
            {
                this.props.Remove(key);
            }
        }
    }
}